package com.ysw.sql;

import com.ysw.annotation.*;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class Mysession implements InvocationHandler {

    private Object subject;

    /**
     * 构造方法，给我们要代理的真实对象赋初值
     *
     * @param subject
     */
    public Mysession(Object subject) {
        this.subject = subject;
    }

    /**
     * 该方法负责集中处理动态代理类上的所有方法调用。 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
     *
     * @param proxy
     *            代理类实例
     * @param method
     *            被调用的方法对象
     * @param args
     *            调用参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 判断方法上是否有ExtInsert注解
        ExtInsert extInsert = method.getAnnotation(ExtInsert.class);
        if (extInsert != null) {
            return insertSQL(extInsert, method, args);
        }
        // 判断方法上是否有ExtSelect注解
        ExtSelect extSelect = method.getAnnotation(ExtSelect.class);
        if (extSelect != null) {
            return selectMybatis(extSelect, method, args);
        }
        // 判断方法上是否有ExtDelete注解
        ExtDelete extDelete = method.getAnnotation(ExtDelete.class);
        if(extDelete != null) {
            deleteSQL(extDelete,method,args);
            return null;
        }
        // 判断方法上是否有ExtUpdate注解
        ExtUpdate extUpdate =  method.getAnnotation(ExtUpdate.class);
        if(extUpdate != null) {
            updateSQL(extUpdate,method,args);
            return null;
        }
        return null;
    }

    private void updateSQL(ExtUpdate extUpdate, Method method, Object[] args) {
        String updateSql = extUpdate.value();
        System.out.println("sql:" + updateSql);
        Parameter[] parameters = method.getParameters();
        ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
        String[] sqlParameter = MysqlUnit.sqlInsertParameter(updateSql);
        List<Object> parameValues = new ArrayList<>();
        for (int i = 0; i < sqlParameter.length; i++) {
            String str = sqlParameter[i];
            Object object = parameterMap.get(str);
            parameValues.add(object);
        }
        String newSql = MysqlUnit.parameQuestion(updateSql, sqlParameter);
        System.out.println("newSql:" + newSql);
        JDBCUnit.execute(newSql, parameValues.get(0),parameValues.get(1));
    }

    private void deleteSQL(ExtDelete extDelete, Method method, Object[] args) {
        String deleteSql = extDelete.value();
        System.out.println("sql:" + deleteSql);
        String newSql = MysqlUnit.parameQuestion(deleteSql, new String[] {"id"});
        System.out.println("newSql:" + newSql);
        JDBCUnit.execute(newSql, args[0]);
    }

    public int insertSQL(ExtInsert extInsert, Method method, Object[] args) {
        String insertSql = extInsert.value();
        System.out.println("sql:" + insertSql);
        Parameter[] parameters = method.getParameters();
        ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
        String[] sqlParameter = MysqlUnit.sqlInsertParameter(insertSql);
        List<Object> parameValues = new ArrayList<>();
        for (int i = 0; i < sqlParameter.length; i++) {
            String str = sqlParameter[i];
            Object object = parameterMap.get(str);
            parameValues.add(object);
        }
        String newSql = MysqlUnit.parameQuestion(insertSql, sqlParameter);
        System.out.println("newSql:" + newSql);
        int insertResult = JDBCUnit.insert(newSql, false, parameValues);
        return insertResult;
    }

    public Object selectMybatis(ExtSelect extInsert, Method method, Object[] args) throws SQLException {
        try {
            String selectSQL = extInsert.value();
            Parameter[] parameters = method.getParameters();
            ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
            List<String> sqlSelectParameter = MysqlUnit.sqlSelectParameter(selectSQL);
            List<Object> parameValues = new ArrayList<>();
            for (int i = 0; i < sqlSelectParameter.size(); i++) {
                String parameterName = sqlSelectParameter.get(i);
                Object object = parameterMap.get(parameterName);
                parameValues.add(object.toString());
            }
            String newSql = MysqlUnit.parameQuestion(selectSQL, sqlSelectParameter);
            System.out.println("执行SQL:" + newSql + "参数信息:" + parameValues.toString());
            ResultSet rs = JDBCUnit.query(newSql, parameValues);
            Class<?> returnType = method.getReturnType();
            if (!rs.next()) {
                return null;
            }
            rs.previous();
            Object newInstance = returnType.newInstance();
            while (rs.next()) {
                for (String parameterName : sqlSelectParameter) {
                    Object value = rs.getObject(parameterName);
                    Field field = returnType.getDeclaredField(parameterName);
                    field.setAccessible(true);
                    field.set(newInstance, value);
                }

            }
            return newInstance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private ConcurrentHashMap<Object, Object> getExtParams(Parameter[] parameters, Object[] args) {
        ConcurrentHashMap<Object, Object> parameterMap = new ConcurrentHashMap<>();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            ExtParam extParam = parameter.getDeclaredAnnotation(ExtParam.class);
            String paramValue = extParam.value();
            Object oj = args[i];
            parameterMap.put(paramValue, oj);
        }
        return parameterMap;
    }
}
